#include "profile/profile.h"

#include <iostream>
#include <fstream>
#include <sstream>

void profile::trim(std::string & s) const {
	if (s.empty())
		return;
	std::string blanks(" \t\n\r");
	std::string::iterator i;
	i = s.begin();
	while (blanks.find(* i) != std::string::npos)
		++i;
	s.erase(s.begin(), i);
	if (s.empty())
		return;
	i = s.end();
	while (blanks.find(* (i - 1)) != std::string::npos)
		--i;
	s.erase(i, s.end());
}

profile::profile(const char * filename, bool use_exceptions) {
	m_use_exceptions = use_exceptions;
	init(filename);
}

profile::profile(std::istream & in, bool use_exceptions) {
	m_use_exceptions = use_exceptions;
	init(in);
}

void profile::init(const char *filename) {
	std::fstream fs(filename, std::ios::in);
	if (m_use_exceptions && !fs) 
		throw CantOpenFile(std::string("Can't open profile file: ") + filename); 
	init(fs);
}

void profile::init(std::istream & in) {
	char buf[1024];
	while (in.getline(buf, 1024)) {
		std::string line(buf), name, value;
		std::string::size_type pos;
		if ((pos = line.find_first_of(';')) != std::string::npos) 
			line.erase(pos);
		if (line.empty())
			continue;
		if (line.substr(0, 8) == "#include") {
			pos = line.find_first_of("<\"");
			std::string::size_type pos1;
			pos1 = line.find_last_of(">\"");
			if (pos == std::string::npos || pos1 == std::string::npos || pos1 <= pos+1)
				if (m_use_exceptions)
					throw CantInclude();
				else
					continue;

			std::string filename = line.substr(pos+1, pos1-pos-1).c_str();
			std::fstream fs(filename.c_str(), std::ios::in);
			if (m_use_exceptions && !fs) 
				throw CantInclude(std::string("Can't include file: ") + filename); 
			init(fs); //!no check for infinite recursion
			continue;
		}
		pos = line.find_first_of('=');
		if (pos != std::string::npos) {
			std::string name = line.substr(0, pos);
			trim(name);
			std::string value = line.substr(pos + 1);
			trim(value);
			if (value.empty()) {
				items_t::iterator v(items.find(name));
				if (v != items.end())
					items.erase(v);
			} else
				items[name].str = value;
		}
	}
}

profile::~profile() {
}

std::ostream & operator << (std::ostream & s, const profile & p)
{
	profile::items_t::const_iterator ii;
	for (ii = p.items.begin(); ii != p.items.end(); ++ii)
		s << ii->first << " = " << ii->second.str << "\n";
	return s;
}

bool profile::has_unused_params(std::string * name) const
{
	items_t::const_iterator ii;
	for (ii = items.begin(); ii != items.end(); ++ii) {
		if (!ii->second.read_once) {
			if (name)
				*name = ii->first;
			if (m_use_exceptions)
				throw Unexpected().append(ii->first);
			return true;
		}
	}
	return false;
}


